﻿using System;
using System.Threading;

#if WINDOWS_PHONE
namespace Fibre.WP7.Threading
#else
#if SILVERLIGHT
namespace Fibre.Silverlight.Threading
#else
namespace Fibre.Threading
#endif
#endif
{
    public static class AsyncSynchroniser
    {
        public static Action MakeSynchronous(
            Func<AsyncCallback, object, IAsyncResult> work,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                complete(result);
            };
        }

        public static Func<T> MakeSynchronous<T>(
            Func<AsyncCallback, object, IAsyncResult> work,
            Func<IAsyncResult, T> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                return complete(result);
            };
        }

        public static Action MakeSynchronous<T>(
            Func<T, AsyncCallback, object, IAsyncResult> work, T asyncArgument,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                complete(result);
            };
        }

        public static Func<TResult> MakeSynchronous<TArg, TResult>(
            Func<TArg, AsyncCallback, object, IAsyncResult> work, 
            TArg asyncArgument,
            Func<IAsyncResult, TResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                return complete(result);
            };
        }

        public static Action MakeSynchronous<TArg, TArg2>(
            Func<TArg, TArg2, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument, 
            TArg2 asyncArgument2,
            Action<IAsyncResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, asyncArgument2, rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                complete(result);
            };
        }

        public static Func<TResult> MakeSynchronous<TArg, TArg2, TResult>(
            Func<TArg, TArg2, AsyncCallback, object, IAsyncResult> work,
            TArg asyncArgument, 
            TArg2 asyncArgument2, 
            Func<IAsyncResult, TResult> complete,
            int timeout = 5000)
        {
            return () =>
            {
                var waitHandle = new ManualResetEvent(false);
                var result = work(asyncArgument, asyncArgument2, rr => waitHandle.Set(), null);
                waitHandle.WaitOne();
                return complete(result);
            };
        }
    }
}
